// 自定义类型Class
type Constructor = new (...args: any[]) => {}

interface Person {
  introduce():void
  getTime():void
}

// 装饰器：使用装饰器重写toString方法 + 封闭其原型对象
function CustomToString(target: Constructor) {
  // 向被装饰类的原型上添加自定义的 toString 方法
  target.prototype.toString = function () {
    return JSON.stringify(this)
  }
  // 封闭其原型对象，禁止随意操作其原型对象
  Object.seal(target.prototype)
}

// 装饰器工厂：定义一个装饰器工厂 LogInfo，它接受一个参数 n，返回一个类装饰器
function LogInfo(n:number) {
  // 装饰器函数，target 是被装饰的类
  return function(target: Constructor){
    target.prototype.introduce = function () {
      for (let i = 0; i < n; i++) {
        console.log(`我的名字：${this.name}，我的年龄：${this.age}`)
      }
    }
  }
}

// 装饰器：创建一个装饰器，为类添加日志功能和创建时间
function LogTime<T extends Constructor>(target: T) {
  return class extends target {
    createdTime: Date;
    constructor(...args: any[]) {
      super(...args);
      this.createdTime = new Date(); // 记录对象创建时间
    }
    getTime() {
      return `该对象创建时间为：${this.createdTime}`;
    }
  };
}


@CustomToString
@LogInfo(5)
@LogTime
class Person {
  constructor(
    public name: string,
    public age: number
  ) {}
  speak() {
    console.log('你好呀！')
  }
}

const p1 = new Person('张三', 18)
p1.speak()  // 你好呀！
console.log(p1.toString())  // {"name":"张三","age":18,"createdTime":"2024-09-10T15:06:18.559Z"}
p1.introduce()  // 5 我的名字：张三，我的年龄：18
console.log(p1.getTime())   // 该对象创建时间为：Tue Sep 10 2024 23:07:42 GMT+0800 (中国标准时间)